#include "datastructure.h"
#include "lanefunction.h"
#include "vehplateutils.h"
#include <QtEndian>
#include <QTextStream>
#include <QDebug>


ObuInfo::ObuInfo(QObject *parent) :
    QObject(parent)
{
    memset(&m_rawSysInfoFile, 0, sizeof m_rawSysInfoFile);
    memset(&m_rawCfg, 0, sizeof m_rawCfg);
}

bool ObuInfo::setObuInfo(const quint8 *sysInfo, quint8 sizeOfSysInfo, const quint8 *obuCfg)
{
    if((sizeOfSysInfo < MIN_SYSFILE_SIZE) ||
            (sizeOfSysInfo > sizeof(m_rawSysInfoFile)))
    {
        qDebug() << "sizeOfSysInfo 字节数不合法";
        return false;
    }
    RawObuSysInfoFile rawSys;
    memset(&rawSys,0,sizeof rawSys);
    memcpy(&rawSys, sysInfo, sizeOfSysInfo);
    QDate d1,d2;
    if(!bcd2date(&d1,rawSys.contractSignedDate))
    {
        qDebug() << "OBU注册时间非法";
        return false;
    }
    if (!bcd2date(&d2, rawSys.contractExpiredDate))
    {
        qDebug() << "OBU过期时间非法";
        return false;
    }

    this->m_contractSignedDate = d1;
    this->m_contractExpiredDate = d2;
    memcpy(&this->m_rawSysInfoFile, &rawSys, sizeof rawSys);
    memcpy(&this->m_rawCfg, obuCfg, OBU_CFG_SIZE);
    // 对山东发行的OBU，解析其系统文件内的车牌和车牌颜色
    // "\xc9\xbd\xb6\xab": "山东"的GB2312编码
    if (0==memcmp("\xc9\xbd\xb6\xab", rawSys.contractProvider, 4))
    {
        setVehPlateNumber(rawSys.vehicleLicencePlateNumber, sizeof(rawSys.vehicleLicencePlateNumber));
        setVehPlateColor(rawSys.vehicleLicencePlateColor[0], rawSys.vehicleLicencePlateColor[1]);
    }
    return true;
}

void ObuInfo::setVehPlateNumber(quint8 *pPlate, int nLen)
{
    // 车牌转换为UTF-8
    QByteArray ba((char *)pPlate, nLen);
    // 正常车牌以\x00结束
    ba.replace('\x00', ' ');
    // 有的测试OBU没有在系统信息文件中写车牌，该部分填充全\xFF，已经查询过GB2312编码没有\xFF
    ba.replace('\xFF', ' ');
    m_vehicleLicencePlateNumber=QTextCodec::codecForName("GB2312")->toUnicode(ba).trimmed();
}

void ObuInfo::setVehPlateColor(quint8 bHi, quint8 bLo)
{
    // 车牌颜色，确实存在车牌相同、车牌颜色不同的车辆，所以必须要存储车牌颜色
    if ((0xFF==bHi) ||
        (0xFF==bLo))
    {
        // 有的OBU没有写车牌颜色
        m_vehicleLicencePlateColor=0;
    }
    else
    {
        m_vehicleLicencePlateColor=bLo;
    }
}

bool ObuInfo::setObuInfo(const QString &sysInfo, const QString &obuCfg)
{
    if(sysInfo.length() > MAX_SYSFILE_SIZE*2)
        return false;
    if(obuCfg.length()!=OBU_CFG_SIZE*2)
        return false;
    quint8 rawSys[MAX_SYSFILE_SIZE];
    quint8 rawCfg[OBU_CFG_SIZE];
    if (!hex2Raw(rawSys, sysInfo.toStdString().c_str(), sysInfo.length()))
    {
        return false;
    }
    if (!hex2Raw(rawCfg, obuCfg.toStdString().c_str(), obuCfg.length()))
    {
        return false;
    }
    return setObuInfo(rawSys, sysInfo.length()/2, rawCfg);
}

bool ObuInfo::setCipheredVehInfoFile(const quint8 *vehInfoFile, quint8 fileLen)
{
    memcpy(this->m_cipheredVehInfo, vehInfoFile, fileLen);
    return true;
}

quint32 ObuInfo::getMacId() const
{
    return qFromBigEndian(this->m_rawCfg.macID);
}

bool ObuInfo::getTampered() const
{
    return testBit(this->m_rawCfg.obuStatus, 1);
}

bool ObuInfo::getLocked() const
{
    return !testBit(this->m_rawCfg.obuStatus, 2);
}

bool ObuInfo::hasCpuCard() const
{
    bool iccPresent=!testBit(this->m_rawCfg.obuStatus, 7);
    bool iccIsCpuCard=!testBit(this->m_rawCfg.obuStatus, 4);
    bool iccStatus=!testBit(this->m_rawCfg.obuStatus, 3);
    return iccPresent && iccIsCpuCard && iccStatus;
}

bool ObuInfo::isFromShandong() const
{
    return 0==memcmp("\xc9\xbd\xb6\xab", this->m_rawSysInfoFile.contractProvider, 4);
}

QString ObuInfo::getContractSN() const
{
    char szSN[20];
    raw2HexStr(szSN, this->m_rawSysInfoFile.contractSerialNumber, sizeof this->m_rawSysInfoFile.contractSerialNumber);
    return szSN;
}

QDate ObuInfo::getSignedDate() const
{
    return this->m_contractSignedDate;
}

QDate ObuInfo::getExpiredDate() const
{
    return this->m_contractExpiredDate;
}

QString ObuInfo::getVehicleLicencePlateNumber() const
{
    return this->m_vehicleLicencePlateNumber;
}

QString ObuInfo::getVehicleLicencePlateColorAndNumber() const
{
    return VehPlateUtils::getVehicleLicencePlateColorAndNumber(
        getVehicleLicencePlateColor(),
        getVehicleLicencePlateNumber());
}

quint16 ObuInfo::getVehicleLicencePlateColor() const
{
    return this->m_vehicleLicencePlateColor;
}

///////////////////////////////////////////////////////////

IccInfo::IccInfo(QObject *parent) :
    QObject(parent)
{
    memset(&this->m_rawIccFile0015, 0, sizeof this->m_rawIccFile0015);
    memset(&this->m_rawIccXinlian0015, 0, sizeof this->m_rawIccXinlian0015);
    memset(&this->m_xinlianTermNo, 0, sizeof this->m_xinlianTermNo);
    this->m_isXinlianCard=false;
    this->m_nGbBalance=0;
    this->m_nXinlianBalance=0;
}

QString IccInfo::toString() const
{
    QString rlt;
    char szBuf[64];
    rlt.append("卡号|");
    rlt.append(QByteArray((char *)m_rawIccXinlian0015.cardNo, 8).toHex());
    rlt.append("|卡类型|");
    szBuf[0]=m_rawIccXinlian0015.cardType;
    szBuf[1]=m_rawIccXinlian0015.subType;
    rlt.append(QByteArray(szBuf, 2).toHex());
    rlt.append("|卡片应用范围|");
    rlt.append(QByteArray((char *)m_rawIccXinlian0015.scope, 2).toHex());
    rlt.append("|交易时间|");
    rlt.append(m_deductTime.toString("yyyyMMddhhmmss"));
    rlt.append("|交易前余额|");
    quint32 balance=qToBigEndian(m_rawIccInitForPurchaseRlt.balanceBeforeInBigEndian);
    double f = balance;
    rlt.append(QString::number(f/100, 'f', 2));
    rlt.append("|交易金额|");
    f = this->m_nMoneyToDeduct;
    rlt.append(QString::number(f/100, 'f', 2));
    rlt.append("|折扣率|");
    f = 0;
    rlt.append(QString::number(f/100, 'f', 2));
    rlt.append("|PSAM卡号|");
    rlt.append(QByteArray((char *)m_xinlianPsamId, 10).toHex());
    rlt.append("|TAC码|");
    rlt.append(QByteArray((char *)m_rawIccTacRlt.tac, 4).toHex().toUpper());
    rlt.append("|终端批次号|");
    rlt.append("?");
    rlt.append("|终端流水号|");
    rlt.append("?");
    rlt.append("|卡片计数器|");
    rlt.append(QString::number(qToBigEndian(m_rawIccInitForPurchaseRlt.transNoInBigEndian)));
    rlt.append("|交易类型标识|");
    rlt.append("09");
    rlt.append("|终端机编号|");
    rlt.append(QByteArray((char *)m_xinlianTermNo, 6).toHex().toUpper());
    rlt.append("|终端交易序列号|");
    rlt.append(QString::number(qToBigEndian(m_rawIccMac1Rlt.termTransNoInBigEndian)));
    return rlt;
}

bool IccInfo::setIcc0015(const quint8 *icc0015, quint8 sizeOfIcc0015)
{
    if (sizeOfIcc0015!=DF01_0015_SIZE)
    {
        qDebug()<<"信联卡信息大小非法";
        return false;
    }
    memcpy(&this->m_rawIccFile0015, icc0015, sizeOfIcc0015);
    // 清空原有信联卡信息
    memset(&this->m_rawIccXinlian0015, 0, sizeof this->m_rawIccXinlian0015);
    this->m_nGbBalance=0;
    this->m_nXinlianBalance=0;
    return true;
}

bool IccInfo::setIcc0015(const QString &icc0015)
{
    if (icc0015.length()!=IccInfo::DF01_0015_SIZE*2)
    {
        return false;
    }
    quint8 raw0015[IccInfo::DF01_0015_SIZE];
    if (!hex2Raw(raw0015, icc0015.toStdString().c_str(), icc0015.length()))
    {
        return false;
    }
    return this->setIcc0015(raw0015, icc0015.length()/2);
}

bool IccInfo::setGbBalance(const quint8 *rawBalance, quint8 sizeOfBalance)
{
    if (sizeOfBalance!=DF01_BALANCE_SIZE)
    {
        qDebug() << "国标余额长度非法";
        return false;
    }

    quint32 nRawBalance;
    memcpy(&nRawBalance, rawBalance, 4);
    this->m_nGbBalance=qFromBigEndian(nRawBalance);
    return true;
}

bool IccInfo::setXinlianBaseInfo(const quint8 *xinlian0015, quint8 sizeOfXinlian0015)
{
    if (sizeOfXinlian0015!=DF02_0015_SIZE)
    {
        qDebug()<<"信联0015文件非法";
        return false;
    }
    RawIccXinlian0015 rawXinlian0015;
    memcpy(&rawXinlian0015, xinlian0015, sizeOfXinlian0015);
    QDate d1, d2;
    if (!bcd2date(&d1, rawXinlian0015.startTime))
    {
        qDebug() << "信联卡启用时间非法";
        return false;
    }
    if (!bcd2date(&d2, rawXinlian0015.expireTime))
    {
        qDebug() << "信联卡到期时间非法";
        return false;
    }
    this->m_startTime=d1;
    this->m_expireTime=d2;
    memcpy(&this->m_rawIccXinlian0015, &rawXinlian0015, sizeof rawXinlian0015);
    return true;
}

bool IccInfo::setXinlianBalance(const quint8 *rawBalance)
{
    quint32 nRawBalance;
    memcpy(&nRawBalance, rawBalance, 4);
    this->m_nXinlianBalance=qFromBigEndian(nRawBalance);
    return true;
}

bool IccInfo::setXinlianBaseInfo(const QString &xinlian0015)
{
    if (xinlian0015.length()!=DF02_0015_SIZE*2)
    {
        return false;
    }
    quint8 rawXinlian0015[DF02_0015_SIZE];
    if (!hex2Raw(rawXinlian0015, xinlian0015.toStdString().c_str(), xinlian0015.length()))
    {
        return false;
    }
    return setXinlianBaseInfo(rawXinlian0015, xinlian0015.length()/2);
}

bool IccInfo::setXinlianBalance(const QString &balance)
{
    if (balance.length()!=4*2)
    {
        return false;
    }
    quint8 rawBalance[4];
    if (!hex2Raw(rawBalance, balance.toStdString().c_str(), balance.length()))
    {
        return false;
    }
    return setXinlianBalance(rawBalance);
}

bool IccInfo::setXinlianInfoForPurchase(const quint8 *initPurchaseRlt)
{
    setXinlianBalance(initPurchaseRlt);
    memcpy(&m_rawIccInitForPurchaseRlt, initPurchaseRlt, sizeof m_rawIccInitForPurchaseRlt);
    return true;
}

bool IccInfo::setXinlianInfoForPurchase(const QString &initPurchaseRlt)
{
    const int RLT_SIZE=sizeof(RawIccInitForPurchaseRlt);
    if (initPurchaseRlt.length()!=RLT_SIZE*2)
    {
        return false;
    }
    quint8 rawRlt[RLT_SIZE];
    if (!hex2Raw(rawRlt, initPurchaseRlt.toStdString().c_str(), initPurchaseRlt.length()))
    {
        return false;
    }
    return setXinlianInfoForPurchase(rawRlt);
}

bool IccInfo::setXinlianMac1(const quint8 *mac1Rlt)
{
    memcpy(&m_rawIccMac1Rlt, mac1Rlt, sizeof m_rawIccMac1Rlt);
    return true;
}

bool IccInfo::setXinlianMac1(const QString &mac1Rlt)
{
    const int RLT_SIZE=sizeof(RawIccMac1Rlt);
    if (mac1Rlt.length()!=RLT_SIZE*2)
    {
        return false;
    }
    quint8 rawRlt[RLT_SIZE];
    if (!hex2Raw(rawRlt, mac1Rlt.toStdString().c_str(), mac1Rlt.length()))
    {
        return false;
    }
    return setXinlianMac1(rawRlt);
}

bool IccInfo::setXinlianTac(const quint8 *tacRlt)
{
    memcpy(&m_rawIccTacRlt, tacRlt, sizeof m_rawIccTacRlt);
    return true;
}

bool IccInfo::setXinlianTac(const QString &tacRlt)
{
    const int RLT_SIZE=sizeof(RawIccTacRlt);
    if (tacRlt.length()!=RLT_SIZE*2)
    {
        return false;
    }
    quint8 rawRlt[RLT_SIZE];
    if (!hex2Raw(rawRlt, tacRlt.toStdString().c_str(), tacRlt.length()))
    {
        return false;
    }
    return setXinlianTac(rawRlt);
}

bool IccInfo::setXinlianTacFromGetTransactionProve(const quint8 *tacRlt)
{
    RawIccTacRlt tmp;
    memcpy(&tmp, tacRlt, sizeof tmp);
    memcpy(m_rawIccTacRlt.tac, tmp.mac2, 4);
    memcpy(m_rawIccTacRlt.mac2, tmp.tac, 4);
    return true;
}

bool IccInfo::setXinlianTacFromGetTransactionProve(const QString &tacRlt)
{
    const int RLT_SIZE=sizeof(RawIccTacRlt);
    if (tacRlt.length()!=RLT_SIZE*2)
    {
        return false;
    }
    quint8 rawRlt[RLT_SIZE];
    if (!hex2Raw(rawRlt, tacRlt.toStdString().c_str(), tacRlt.length()))
    {
        return false;
    }
    return setXinlianTacFromGetTransactionProve(rawRlt);
}

bool IccInfo::setTermNo(const QString &termNo)
{
    const int RLT_SIZE=6;
    if (termNo.length()!=RLT_SIZE*2)
    {
        return false;
    }
    quint8 rawRlt[RLT_SIZE];
    if (!hex2Raw(rawRlt, termNo.toStdString().c_str(), termNo.length()))
    {
        return false;
    }
    return setTermNo(rawRlt);
}

bool IccInfo::setDeductInfo(quint32 nMoneyToDeduct, QDateTime deductTime)
{
    this->m_nMoneyToDeduct = nMoneyToDeduct;
    this->m_deductTime = deductTime;
    return true;
}

quint8 *IccInfo::getInitSamForPurchaseCmd() const
{
    //命令报文规范
    //CLA: 80, INS: 70, P1: 00, P2: 00, Lc: 0x14+8*N(N=2)
    //Data: 用户卡随机数R_icc(4bytes) || 用户卡脱机交易序列号NT_OFF_XX(2 bytes) ||
    //      交易金额M_P(4bytes) || 交易类型标识NT_IND(1byte) ||
    //      终端交易日期 DATE_TERM(4bytes) || 终端交易时间TIME_TERM(3bytes) ||
    //      消费密钥版本号 VK(1byte) || 消费密钥算法标识ALGK(1byte) || 应用序列号APP_NR (8bytes) ||
    //      城市标识符 CITY_ID(8 bytes)
    static quint8 cmd[48];
    cmd[0]=41;              // length of cmd
    cmd[1]=0x80;            // CLA
    cmd[2]=0x70;            // INS
    cmd[3]=0x00;            // P1
    cmd[4]=0x00;            // P2
    cmd[5]=0x24;            // Lc
    memcpy(cmd+6, m_rawIccInitForPurchaseRlt.random, 4);
    memcpy(cmd+10, &m_rawIccInitForPurchaseRlt.transNoInBigEndian, 2);
    quint32 nMoneyToDeduct=qToBigEndian(this->m_nMoneyToDeduct);
    memcpy(cmd+12, &nMoneyToDeduct, 4);
    cmd[16]=0x09;
    systime2bcd((char *)cmd+17, 7, this->m_deductTime);
    cmd[24]=0x01;
    cmd[25]=0x00;
    memcpy(cmd+26, m_rawIccXinlian0015.cardNo, 8);
    memset(cmd+34, 0, 8);
    return cmd;
}

quint8 *IccInfo::getUpdateRecord0017Cmd() const
{
    RawIccXinlian0017 icc0017;
    memset(&icc0017, 0, sizeof icc0017);
    icc0017.flag = 0x09;
    icc0017.dataLen = 0x2E;
    icc0017.locked = 0x00;
    icc0017.version = 0x01;
    icc0017.transFlag = 0x00;
    memcpy(&icc0017.termNo, this->m_xinlianTermNo, sizeof this->m_xinlianTermNo);
    icc0017.moneyToDeductBigEndian = qToBigEndian(this->m_nMoneyToDeduct);
    systime2bcd((char *)icc0017.deductTime, 7, this->m_deductTime);
    memcpy(&icc0017.mac1, this->m_rawIccMac1Rlt.mac1, 4);

    //命令报文规范
    //CLA: 80, INS: DC, P1: 指定记录号(00为当前记录号), P2: 记录选择, Lc: 记录长度（要更新的数据的长度，最大值为卡的buffer 长度）
    //Data: 记录数据
    static quint8 cmd[56];
    cmd[0]=0x35;            // length of cmd
    cmd[1]=0x80;            // CLA
    cmd[2]=0xDC;            // INS
    cmd[3]=0x09;            // P1: 复合消费标志（09：全国通用消费）
    cmd[4]=0x17<<3;         // P2
    cmd[5]=0x30;            // Lc
    memcpy(cmd+6, &icc0017, sizeof icc0017);
    return cmd;
}

quint8 *IccInfo::getDebitForCappPurchaseCmd() const
{
    //命令报文规范
    //CLA: 80, INS: 54, P1: 01, P2: 00, Lc: 0F
    //Data: 终端交易序号(4字节)+交易日期(4字节)+交易时间(3字节)+MAC1(4字节), Le: 08
    static quint8 cmd[32];
    cmd[0]=21;              // length of cmd
    cmd[1]=0x80;            // CLA
    cmd[2]=0x54;            // INS
    cmd[3]=0x01;            // P1: 复合消费标志（09：全国通用消费）
    cmd[4]=0x00;            // P2
    cmd[5]=0x0F;            // Lc
    memcpy(cmd+6, &this->m_rawIccMac1Rlt.termTransNoInBigEndian, 4);
    systime2bcd((char *)cmd+10, 7, this->m_deductTime);
    memcpy(cmd+17, this->m_rawIccMac1Rlt.mac1, 4);
    cmd[21]=0x08;
    return cmd;
}

quint8 *IccInfo::getCreditSamForPurchaseCmd() const
{
    //命令报文规范
    //CLA: 80, INS: 72, P1: 00, P2: 00, Lc: 04
    //Data: MAC2(4字节)
    static quint8 cmd[16];
    cmd[0]=9;              // length of cmd
    cmd[1]=0x80;            // CLA
    cmd[2]=0x72;            // INS
    cmd[3]=0x00;            // P1
    cmd[4]=0x00;            // P2
    cmd[5]=0x04;            // Lc
    memcpy(cmd+6, this->m_rawIccTacRlt.mac2, 4);
    return cmd;
}

quint8 *IccInfo::getTransactionProveCmd() const
{
    //命令报文规范
    //CLA: 80, INS: 5A, P1: 00, P2: 要取MAC或TAC所对应的交易类型标识, Lc: 02
    //Data: 要取MAC或交易认证码所对应的当前的电子存折或电子钱包联机或脱机交易序号(2字节)
    //Le: 08
    static quint8 cmd[16];
    cmd[0]=8;              // length of cmd
    cmd[1]=0x80;            // CLA
    cmd[2]=0x5A;            // INS
    cmd[3]=0x00;            // P1
    cmd[4]=0x09;            // P2
    cmd[5]=0x02;            // Lc
    quint16 transNo=qToBigEndian(m_rawIccInitForPurchaseRlt.transNoInBigEndian);
    transNo++;
    transNo=qToBigEndian(transNo);
    memcpy(cmd+6, &transNo, 2);
    cmd[8]=0x08;
    return cmd;
}

bool IccInfo::isDateValid()
{
    QDate current=QDate::currentDate();
    return (current>=this->m_startTime) &&
           (current<=this->m_expireTime);
}

QString IccInfo::getGBNetworkNo() const
{
    char szNetworkNo[8];
    raw2HexStr(szNetworkNo, this->m_rawIccFile0015.cardNetwork,
               sizeof this->m_rawIccFile0015.cardNetwork);
    return szNetworkNo;
}

QString IccInfo::getGBCardNo() const
{
    char szCardNo[20];
    raw2HexStr(szCardNo, this->m_rawIccFile0015.cardNo,
               sizeof this->m_rawIccFile0015.cardNo);
    return szCardNo;
}

QString IccInfo::getGBCardNoWithNetworkNo() const
{
    return this->getGBNetworkNo()+this->getGBCardNo();
}

QString IccInfo::getVehicleLicencePlateNumber() const
{
    // 车牌转换为UTF-8
    QByteArray ba((char *)m_rawIccFile0015.vehicleLicencePlateNumber, sizeof m_rawIccFile0015.vehicleLicencePlateNumber);
    // 正常车牌以\x00结束
    ba.replace('\x00', ' ');
    ba.replace('\xFF', ' ');
    return QTextCodec::codecForName("GB2312")->toUnicode(ba).trimmed();
}

int IccInfo::getVehicleLicencePlateColor() const
{
    return m_rawIccFile0015.vehicleLicencePlateColor;
}

QString IccInfo::getXinlianCardNo() const
{
    char szCardNo[20];
    raw2HexStr(szCardNo, this->m_rawIccXinlian0015.cardNo,
               sizeof this->m_rawIccXinlian0015.cardNo);
    return szCardNo;
}


